/**
**************************************************************************************
*Founder Effect                                                                      *
*Copyright (C) 2006-2007, 5d Studios (www.5d-Studios.com)                            *
*                                                                                    *
*This library is free software; you can redistribute it and/or                       *
*modify it under the terms of the GNU Lesser General Public                          *
*License as published by the Free Software Foundation; either                        *
*version 2.1 of the License, or (at your option) any later version.                  *
*                                                                                    *
*This library is distributed in the hope that it will be useful,                     *
*but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                   *
*Lesser General Public License for more details.                                     *
*                                                                                    *
*You should have received a copy of the GNU Lesser General Public                    *
*License along with this library; if not, write to the Free Software                 *
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA      *
**************************************************************************************
*/
#include "StdAfx.h"
#include <iostream>

#include "LuaEngine.h"
#include "LuaStackguard.h"
#include "../shared/StringUtil.h"

#include "../Kernel.h"
 
extern Kernel* g_kernel;

// TODO - Move me
#include "LUA_Console.h"    // we should add components through an interface: m_luaEngine->AddComponent( LUA_Console )

/** ------Forward decl. functions---------------  */
extern int luaopen_LUA_Console(lua_State *L);   // Pass a func pointer to AddComponent( * );
//extern int luaopen_LUA_Camera(lua_State *L);
//extern int luaopen_LUA_Entity(lua_State *L);
//extern int luaopen_LUA_EntityView(lua_State *L);
//extern int luaopen_LUA_Player(lua_State *L);
//extern int luaopen_LUA_GUI_Manager(lua_State *L);
//extern int luaopen_LUA_GameState(lua_State *L);

LuaEngine::LuaEngine(void)
{
    L = NULL;
}


/** Initalize the lua engine */
int LuaEngine::Init()
{
    L = lua_open();

    
    // Error loading LUA
    if ( !L ) {
        g_kernel->LPrintf( "ERROR:: Could not Initialize LuaEngine--Could not Open LUA!" );
        return 1;
    }
    // standard lua libs
    luaopen_base(L);
    luaopen_string(L);
    luaopen_math(L);

    // MyriadEngine defined 
    luaopen_LUA_Console(L);
    //luaopen_LUA_Camera(L);
    //luaopen_LUA_Entity(L);
    //luaopen_LUA_EntityView(L);
    //luaopen_LUA_Player(L);
    //luaopen_LUA_GUI_Manager(L);
    //luaopen_LUA_GameState(L);
    
    return 0;
}

/** Close off lua */
void LuaEngine::Shutdown()
{
    if ( L )
    {
        lua_close( L );
        L = NULL;
    }
}

/** Execute a file */
int LuaEngine::RunFile(const std::string &filename)
{
    LuaStackguard guard(L);
    if ( filename.size() )
    {
        //MFile file;
        //if ( file.Open( filename ) )
        //{
        //    //std::cout << "loaded\n";
        //    // TODO - doesn't work!
        //    std::cout << "coulnd't load\n";
        //    
        //}
        //else
        //{
        //    return ( luaL_loadbuffer(L, file.GetRawData(), file.Size(), filename.c_str() ) || lua_pcall(L, 0, 0, 0));
        //}

        return (luaL_loadfile(L, filename.c_str()) || lua_pcall(L, 0, 0, 0));
    }
    return 1;   
}

/** Call a lua function */
void LuaEngine::CallFunction(const std::string &name)
{
    LuaStackguard guard(L);

    StringUtil util( name );
    std::string functionName;
    if ( util.HasNext() )
        functionName = util.GetNext();

    lua_getfield(L, LUA_GLOBALSINDEX, functionName.c_str() );
    int numArgs = util.Size();
    
    for( int i = 0; i < numArgs; ++i )
        lua_pushstring( L, util.GetNext().c_str() );
    lua_call( L, numArgs, 0 );

}

/** Set a global int */
void LuaEngine::SetGlobalInt(const std::string name, const int val) 
{
    LuaStackguard guard(L);
    
    lua_pushnumber(L, val);
    lua_setglobal(L, name.c_str());
}

/** Set a global double */
void LuaEngine::SetGlobalDouble(const std::string name, const double val) 
{
    LuaStackguard guard(L);
    
    lua_pushnumber(L, val);
    lua_setglobal(L, name.c_str());
}

/** Set a global string */
void LuaEngine::SetGlobalString(const std::string name, const std::string val)
{
    LuaStackguard guard(L);
    
    lua_pushstring(L, val.c_str());
    lua_setglobal(L, name.c_str());
}

/** Get a global int */
int  LuaEngine::GetGlobalInt(const std::string name) 
{ 
    LuaStackguard guard(L);
    
    int result = 0;
    lua_getglobal(L, name.c_str());
    
    // error loading
    if (!lua_isnumber(L, -1))
        return 0;

    result = int(lua_tonumber(L, -1));
    lua_pop(L, 1);
    return result;
}

/** Get a global double */
double LuaEngine::GetGlobalDouble(const std::string name) 
{ 
    LuaStackguard guard(L);
    
    double result = 0.0;
    lua_getglobal(L, name.c_str());
    
    // error loading
    if (!lua_isnumber(L, -1))
        return 0;

    result = double(lua_tonumber(L, -1));
    lua_pop(L, 1);
    return result;
}

/** Get a global string */
const std::string LuaEngine::GetGlobalString(const std::string name) 
{ 
    LuaStackguard guard(L);
    
    std::string result = 0;
    lua_getglobal(L, name.c_str());
    
    // error loading
    if (!lua_isnumber(L, -1))
        return 0;

    result = (lua_tostring(L, -1));
    lua_pop(L, 1);
    return result;

}


LuaEngine::~LuaEngine(void)
{
    Shutdown();
}
